package com.chuangke.sinotrukbudget.service.impl;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import com.alibaba.druid.util.StringUtils;
import com.alibaba.fastjson2.JSONObject;
import com.aliyun.dingtalktodo_1_0.models.QueryOrgTodoTasksResponseBody.QueryOrgTodoTasksResponseBodyTodoCards;
import com.chuangke.admin.model.SysUser;
import com.chuangke.admin.service.SysUserService;
import com.chuangke.core.id.IdManager;
import com.chuangke.dingtalk.DingTalkService;
import com.chuangke.dingtalk.DingTalkUserInfo;
import com.chuangke.sinotrukbudget.consts.BudgetContanst;
import com.chuangke.sinotrukbudget.service.BudgetDingTalkTodoService;
import com.chuangke.sinotrukbudget.service.BudgetTodoService;

@Service
public class BudgetDingTalkTodoServiceImpl implements BudgetDingTalkTodoService {

    private static Logger logger = LoggerFactory.getLogger(BudgetDingTalkTodoServiceImpl.class);

    @Autowired
    private BudgetTodoService budgetTodoService;
    @Autowired
    private DingTalkService dingTalkService;
    @Autowired
    private SysUserService sysUserService;

    @Async
    @Override
    public synchronized void handleDingTalkTodo(List<String> handleDingTalkUserIdList) {
        /* 异步创建钉钉待办任务，删除钉钉待办任务 */
        /* 等待5秒让其他事务完成 */
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        doHandleDingTalkTodo(handleDingTalkUserIdList);
    }

    @Override
    public void reviseDingTalkTodo() {
        Map<String, SysUser> userMap = sysUserService.findMap();
        List<String> userIdList = userMap.values().stream().map(SysUser::getName).collect(Collectors.toList());
        doHandleDingTalkTodo(userIdList);
    }

    private void doHandleDingTalkTodo(List<String> handleDingTalkUserIdList) {
        logger.info("开始处理钉钉待办任务");

        logger.info("待处理用户量：{}，用户列表：[{}]", handleDingTalkUserIdList.size(), String.join(",", handleDingTalkUserIdList));

        // 获取系统中有待办任务的用户
        List<String> existSystemTodoUserList = budgetTodoService.getTodoUser();
        existSystemTodoUserList = existSystemTodoUserList.stream()
                .filter(handleDingTalkUserIdList::contains).collect(Collectors.toList());

        String accessToken = dingTalkService.getAccessToken();

        // 获取用户的unionId
        Map<String, String> unionIdMap = queryUserUnionId(accessToken, handleDingTalkUserIdList);
        // 获取用户是否存在钉钉待办任务
        Map<String, List<QueryOrgTodoTasksResponseBodyTodoCards>> dingTalkTodoMap = queryDingTalkTodo(accessToken,
                unionIdMap);

        createDingtalkTodo(accessToken, unionIdMap, existSystemTodoUserList, dingTalkTodoMap);

        deleteDingtalkTodo(accessToken, unionIdMap, existSystemTodoUserList, dingTalkTodoMap);

        logger.info("结束处理钉钉待办任务");
    }

    /**
     * @param accessToken
     * @param existSystemTodoUserList
     * @param unionIdMap
     */
    private void createDingtalkTodo(String accessToken, Map<String, String> unionIdMap,
                                    List<String> existSystemTodoUserList,
                                    Map<String, List<QueryOrgTodoTasksResponseBodyTodoCards>> dingTalkTodoMap) {
        // 获取存在系统待办任务，但是不存在钉钉待办任务的用户userid及unionid,供下一步创建钉钉待办任务
        Map<String, String> existsSystemTodoAndNoDingTalkTodoUserMap = new HashMap<>();
        for (String userid : existSystemTodoUserList) {
            if (dingTalkTodoMap.keySet().contains(userid)) {
                logger.info("校验能否为用户[{}]创建待办任务，校验结果：{}，原因：已经存在钉钉待办任务", userid, "不需创建");
                continue;
            }

            existsSystemTodoAndNoDingTalkTodoUserMap.put(userid, unionIdMap.get(userid));
            logger.info("校验能否为用户[{}]创建待办任务，校验结果：{}", userid, "可以创建");
        }
        createDingTalkTodo(accessToken, existsSystemTodoAndNoDingTalkTodoUserMap);
    }

    private void deleteDingtalkTodo(String accessToken, Map<String, String> unionIdMap,
                                    List<String> existSystemTodoUserList,
                                    Map<String, List<QueryOrgTodoTasksResponseBodyTodoCards>> dingTalkTodoMap) {
        // 获取不存在系统待办任务，但是存在钉钉待办任务的用户userid及unionid,供下一步删除钉钉待办任务
        Map<String, String> noSystemTodoAndExistDingTalkTodoUserMap = new HashMap<>();
        for (String userid : unionIdMap.keySet()) {
            if (dingTalkTodoMap.keySet().contains(userid) && !existSystemTodoUserList.contains(userid)) {
                noSystemTodoAndExistDingTalkTodoUserMap.put(userid, unionIdMap.get(userid));

                logger.info("校验能否为用户[{}]删除待办任务，校验结果：{}，原因：存在钉钉待办并且不存在系统待办", userid, "可以删除");

                continue;
            }

            logger.info("校验能否为用户[{}]删除待办任务，校验结果：{}", userid, "不用删除");
        }
        deleteDingTalkTodo(accessToken, noSystemTodoAndExistDingTalkTodoUserMap, dingTalkTodoMap);
    }

    private void createDingTalkTodo(String accessToken, Map<String, String> existsSystemTodoAndNoDingTalkTodoUserMap) {
        existsSystemTodoAndNoDingTalkTodoUserMap.keySet().parallelStream().forEach(userId -> {
            logger.info("开始为用户{}，创建钉钉待办任务", userId);
            String unionId = existsSystemTodoAndNoDingTalkTodoUserMap.get(userId);
            if (StrUtil.isBlank(unionId)) {
                logger.info("用户{}未查询到unionid，无法创建钉钉待办任务", userId);
            } else {
                String sourceId = BudgetContanst.DING_TALK_TODO_PREFIX + IdManager.nextId();
                String subject = "归口审批平台（BPAP）有待审核预算.";
                dingTalkService.createTodo(accessToken, unionId, sourceId, subject);

                logger.info("结束为用户{}，创建钉钉待办任务", userId);
            }
        });
    }

    private void deleteDingTalkTodo(String accessToken, Map<String, String> noSystemTodoAndExistDingTalkTodoUserMap,
                                    Map<String, List<QueryOrgTodoTasksResponseBodyTodoCards>> dingTalkTodoMap) {
        noSystemTodoAndExistDingTalkTodoUserMap.keySet().parallelStream().forEach(userId -> {
            logger.info("开始为用户{}，删除钉钉待办任务", userId);
            String unionId = noSystemTodoAndExistDingTalkTodoUserMap.get(userId);
            if (StrUtil.isBlank(unionId)) {
                logger.info("用户{}未查询到unionid，无法删除钉钉待办任务", userId);
            } else {
                List<QueryOrgTodoTasksResponseBodyTodoCards> todoList = dingTalkTodoMap.get(userId);
                for (QueryOrgTodoTasksResponseBodyTodoCards todo : todoList) {
                    if (todo.getSourceId().startsWith(BudgetContanst.DING_TALK_TODO_PREFIX)) {
                        logger.info("删除钉钉待办任务,sourceId:{};subject:{}", userId, todo.getSourceId(), todo.getSubject());
                        dingTalkService.deleteTodo(accessToken, unionId, todo.getTaskId());
                    }
                }
            }
        });
    }

    /**
     * 批量查询用户的钉钉待办任务
     *
     * @param accessToken
     * @param unionMap
     */
    private Map<String, List<QueryOrgTodoTasksResponseBodyTodoCards>> queryDingTalkTodo(String accessToken,
                                                                                        Map<String, String> unionMap) {
        Map<String, List<QueryOrgTodoTasksResponseBodyTodoCards>> dingTalkTodoMap = new ConcurrentHashMap<>();
        unionMap.keySet().parallelStream().forEach(userId -> {
            if (!StrUtil.isBlank(unionMap.get(userId))) {
                try {
                    List<QueryOrgTodoTasksResponseBodyTodoCards> todoList = dingTalkService.queryTodo(accessToken,
                            unionMap.get(userId));
                    if (isExistDingTalkTodo(todoList)) {
                        dingTalkTodoMap.put(userId, todoList);
                    }

                } catch (Exception e) {
                    logger.error("用户[{}]获取钉钉待办任务异常,异常信息：{}", userId, e.getMessage());
                }
            }
        });
        return dingTalkTodoMap;
    }

    /**
     * 批量查询用户的unionId
     *
     * @param accessToken
     * @param userIdList
     * @return
     */
    private Map<String, String> queryUserUnionId(String accessToken, List<String> userIdList) {
        Map<String, String> unionMap = new ConcurrentHashMap<>();
        userIdList.parallelStream().forEach(userId -> {
            try {
                JSONObject userInfo = dingTalkService.getDetailUserInfo(userId, accessToken);
                DingTalkUserInfo dtUserInfo = new DingTalkUserInfo(userInfo);
                String unionid = dtUserInfo.getUnionId();
                unionMap.put(userId, unionid);
            } catch (Exception e) {
                logger.error("用户[{}]获取unionid异常,异常信息：{}", userId, e.getMessage());
            }
        });
        return unionMap;
    }

    private boolean isExistDingTalkTodo(List<QueryOrgTodoTasksResponseBodyTodoCards> todoList) {
        if (CollectionUtils.isEmpty(todoList)) {
            return false;
        }

        for (QueryOrgTodoTasksResponseBodyTodoCards todo : todoList) {
            if (todo.getSourceId().startsWith(BudgetContanst.DING_TALK_TODO_PREFIX)) {
                return true;
            }
        }

        return false;
    }

}
